package com.atguigu.gulimall.order.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.To.mq.OrderTo;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;
import com.atguigu.common.utils.R;
import com.atguigu.common.vo.MemberVo;
import com.atguigu.gulimall.order.constant.OrderStatusEnum;
import com.atguigu.gulimall.order.constant.Orderconstan;
import com.atguigu.gulimall.order.dao.OrderDao;
import com.atguigu.gulimall.order.entity.OrderEntity;
import com.atguigu.gulimall.order.entity.OrderItemEntity;
import com.atguigu.gulimall.order.exception.NoStockException;
import com.atguigu.gulimall.order.feign.CartFeign;
import com.atguigu.gulimall.order.feign.MemberFeign;
import com.atguigu.gulimall.order.feign.ProductFeign;
import com.atguigu.gulimall.order.feign.WareFeign;
import com.atguigu.gulimall.order.interceptro.OrderLoginInterceptro;
import com.atguigu.gulimall.order.service.OrderItemService;
import com.atguigu.gulimall.order.service.OrderService;
import com.atguigu.gulimall.order.to.OrderCreateTo;
import com.atguigu.gulimall.order.vo.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    private static ThreadLocal<OrderSubmitVo> orderSubmitVoThreadLocal = new ThreadLocal<>();

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    MemberFeign memberFeign;

    @Autowired
    CartFeign cartFeign;

    @Autowired
    ProductFeign productFeign;

    @Autowired
    OrderItemService orderItemService;

    @Autowired
    WareFeign wareFeign;

    @Autowired
    RabbitTemplate rabbitTemplate;

    //本地事务方法内互掉的坑
    //**REQUIRED：如果当前没有事务，就新建一个事务，如果已经存在一个事务中，加入到这个事务中。一般的选择（默认值）**
    @Transactional(propagation = Propagation.REQUIRED)
    public void a(){
        //如果不是方法内互调 a事务失败 则b事务回滚 而c事务不回滚
        b();
        c();

        //如果在方法内互调 则b c方法事务都回滚
        b();
        c();

        //在方法内互调 a回滚事务 c不需要回滚
        OrderServiceImpl o = (OrderServiceImpl) AopContext.currentProxy();
        o.b();
        o.c();

    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void b(){

    }
    //REQUERS_NEW：新建事务，如果当前在事务中，把当前事务挂起
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void c(){

    }


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 提交订单 保存订单信息和订单项信息
     * @param vo
     * @return
     */
    @Override
    public OrderSubmitResponseVo submitOrder(OrderSubmitVo vo) {
        orderSubmitVoThreadLocal.set(vo);
        OrderSubmitResponseVo responseVo = new OrderSubmitResponseVo();
        //用户id获取
        MemberVo memberVo = OrderLoginInterceptro.threadLocal.get();
        String script = "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        //验证令牌
        String orderToken = vo.getOrderToken();
        Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(Orderconstan.ORDER_TOKEN_PREFIX + memberVo.getId()), orderToken);
        if (result == 1L) {
            //令牌验证成功 创建订单信息
            OrderCreateTo createTo = orderCreat();

            //验价 查询到的价格和页面价格是否一致
            BigDecimal payAmount = createTo.getOrderEntity().getPayAmount();
            BigDecimal payPrice = vo.getPayPrice();
            if (Math.abs(payAmount.subtract(payPrice).doubleValue()) < 0.001) {
                //成功
                //保存订单
                saveorder(createTo);
                //锁库存 构建传递给库存的vo
                WareStockVo wareStockVo = new WareStockVo();
                wareStockVo.setOrderSn(createTo.getOrderEntity().getOrderSn()); //订单编号
                List<OrderItemEntity> itemEntities = createTo.getItemEntities();
                //需要用到的订单项信息
                List<OrderItemVo> locaks = itemEntities.stream().map(item -> {
                    OrderItemVo orderItemVo = new OrderItemVo();
                    orderItemVo.setSkuId(item.getSkuId());
                    orderItemVo.setCount(item.getSkuQuantity());
                    orderItemVo.setTitle(item.getSkuName());
                    orderItemVo.setPrice(item.getSkuPrice());
                    return orderItemVo;
                }).collect(Collectors.toList());
                wareStockVo.setOrderItemVos(locaks);
                //远程调用锁库存
                R r = wareFeign.wareStock(wareStockVo);
                if (r.getcode() == 0) {
                    //锁库存成功
                    responseVo.setCode(OrderStatusEnum.CREATE_NEW.getCode());
                    responseVo.setOrderEntity(createTo.getOrderEntity());
                    //发送消息 死信队列  一定时间后路由给order-release-stock
                    rabbitTemplate.convertAndSend("order-event-exchange", "order.locked", createTo.getOrderEntity());
                    return responseVo;
                } else {
                    throw new NoStockException(r.getData(new TypeReference<String>() {
                    }));
                }
            } else {
                //失败
                return null;
            }

        } else {
            responseVo.setCode(10);
            return responseVo;
        }
    }

    /**
     * 根据订单编号获取订单信息
      * @param orderSn
     * @return
     */
    @Override
    public OrderEntity getByOrderSn(String orderSn) {
        return this.baseMapper.selectOne(new QueryWrapper<OrderEntity>().eq("order_sn",orderSn));
    }

    /**
     * 关闭订单
     * @param orderEntity
     */
    @Override
    public void  OrderClose(OrderEntity orderEntity) {
        OrderEntity byId = this.getById(orderEntity.getId());
        //查询订单状态
        if (byId.getStatus()==OrderStatusEnum.CREATE_NEW.getCode()){
            //修改订单状态 为已取消
            byId.setStatus(OrderStatusEnum.CANCLED.getCode());
            updateById(orderEntity);
            OrderTo orderTo = new OrderTo();
            BeanUtils.copyProperties(byId,orderTo);
            //订单状态 发消息给库存 解锁库存 stock-release-stock
            rabbitTemplate.convertAndSend("order-event-exchange","order.release.stock.#",orderTo);
        }
    }

    /**
     * 保存订单
     * @param createTo
     */
    private void saveorder(OrderCreateTo createTo) {
        //保存订单信息
        OrderEntity orderEntity = createTo.getOrderEntity();
        this.baseMapper.insert(orderEntity);
        //保存订单项信息
        List<OrderItemEntity> itemEntities = createTo.getItemEntities();
        orderItemService.saveBatch(itemEntities);
    }

    /**
     * 创建订单信息
     * @return
     */
    private OrderCreateTo orderCreat() {
        OrderCreateTo createTo = new OrderCreateTo();
        //创建订单号
        String timeId = IdWorker.getTimeId();
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(timeId);
        //创建收获地址
        OrderSubmitVo orderSubmitVo = orderSubmitVoThreadLocal.get();
        R addressId = memberFeign.getAddressId(orderSubmitVo.getAddrId());
        FareVo data = addressId.getData(new TypeReference<FareVo>() {
        });
        //封装订单信息
        MemberReceiveAddressEntity address = data.getMemberReceiveAddressEntity();
        orderEntity.setFreightAmount(data.getFare());//运费金额
        orderEntity.setReceiverName(address.getName());//收件人姓名
        orderEntity.setReceiverCity(address.getCity()); //诚实
        orderEntity.setReceiverPhone(address.getPhone());//手机号
        orderEntity.setReceiverDetailAddress(address.getDetailAddress());//详细地址
        orderEntity.setReceiverProvince(address.getProvince());//省份
        orderEntity.setReceiverRegion(address.getRegion()); //区
        orderEntity.setReceiverPostCode(address.getPostCode());//邮编
        orderEntity.setMemberId(address.getMemberId());//会员id
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());//订单状态
        MemberVo memberVo = OrderLoginInterceptro.threadLocal.get();
        //orderEntity.setMemberId(memberVo.getId());//商品id
        //构建订单项
        List<OrderItemEntity> orderItemEntities = buildOrderItems(timeId);
        //计算商品价格
        orderEntity = computePrice(orderEntity, orderItemEntities);


        createTo.setFare(data.getFare());
        createTo.setOrderEntity(orderEntity);
        createTo.setItemEntities(orderItemEntities);

        return createTo;
    }

    /**
     * 计算订单的价格
     * @param orderEntity
     * @param orderItemEntities
     * @return
     */
    private OrderEntity computePrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntities) {
        BigDecimal total = new BigDecimal("0");
        BigDecimal coupon = new BigDecimal("0");
        BigDecimal integration = new BigDecimal("0");
        BigDecimal promotion = new BigDecimal("0");
        for (OrderItemEntity orderItemEntity : orderItemEntities) {
            BigDecimal realAmount = orderItemEntity.getRealAmount();
            total = total.add(realAmount);
            BigDecimal couponAmount = orderItemEntity.getCouponAmount();
            coupon = coupon.add(couponAmount);
            BigDecimal integrationAmount = orderItemEntity.getIntegrationAmount();
            integration = integration.add(integrationAmount);
            BigDecimal promotionAmount = orderItemEntity.getPromotionAmount();
            promotion = promotion.add(promotionAmount);
        }
        orderEntity.setCouponAmount(coupon);
        orderEntity.setIntegrationAmount(integration);
        orderEntity.setPromotionAmount(promotion);
        //应付总额
        orderEntity.setPayAmount(total.add(orderEntity.getFreightAmount()));

        return orderEntity;

    }

    /**
     * 构建订单项信息
     * @param timeId
     * @return
     */
    private List<OrderItemEntity> buildOrderItems(String timeId) {
        //创建订单项
        //查询选择的商品信息
        List<OrderItemVo> cartOrder = cartFeign.getCartOrder();
        //保存订单项信息
        List<OrderItemEntity> collect = cartOrder.stream().map(item -> {
            OrderItemEntity orderItemEntity = new OrderItemEntity();
            orderItemEntity.setOrderSn(timeId);//订单编号
            orderItemEntity = buildOrderItem(item);
            return orderItemEntity;
        }).collect(Collectors.toList());
        return collect;
    }

    /**
     * 构建单个订单项信息
     * @param item
     * @return
     */
    public OrderItemEntity buildOrderItem(OrderItemVo item){
        //获取spu信息
        Long skuId = item.getSkuId();
        R spuInfoSkuId = productFeign.getSpuInfoSkuId(skuId);
        ProductSpuInfoVo data = spuInfoSkuId.getData(new TypeReference<ProductSpuInfoVo>() {
        });
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        orderItemEntity.setSpuId(data.getId());
        orderItemEntity.setSpuBrand(data.getBrandId().toString());
        orderItemEntity.setSpuName(data.getSpuName());
        orderItemEntity.setCategoryId(data.getCatalogId());
        //获取sku信息
        orderItemEntity.setSkuId(skuId);
        orderItemEntity.setSkuName(item.getTitle());
        orderItemEntity.setSkuPic(item.getImg());
        orderItemEntity.setSkuQuantity(item.getCount());
        orderItemEntity.setSkuPrice(item.getPrice());
        String string = StringUtils.collectionToDelimitedString(item.getSkuAttr(), ";");
        orderItemEntity.setSkuAttrsVals(string);
        //积分信息
        orderItemEntity.setGiftGrowth(item.getPrice().intValue());
        orderItemEntity.setGiftIntegration(item.getPrice().intValue());
        //优惠信息
        orderItemEntity.setIntegrationAmount(new BigDecimal("0"));
        orderItemEntity.setCouponAmount(new BigDecimal("0"));
        orderItemEntity.setPromotionAmount(new BigDecimal("0"));
        BigDecimal totalPrice = item.getTotalPrice();
        BigDecimal subtract = totalPrice.subtract(orderItemEntity.getCouponAmount()).subtract(orderItemEntity.getIntegrationAmount()).subtract(orderItemEntity.getPromotionAmount());
        //实际价格
        orderItemEntity.setRealAmount(subtract);
        return orderItemEntity;
    }

}